Quickstart
On this page
End-to-end: from sign-up to a verified user, in about ten minutes.
Prerequisites
- A Self.xyz dashboard account.
- The Self mobile app on your phone (iOS or Android). You’ll verify with a mock passport in step 8.
- Node 20+ (for the SDK).
- A way to receive a webhook locally, ngrok, Cloudflare Tunnel, or any public HTTPS endpoint.
1. Sign up
Sign in with an email code or Google; any email address works. On first sign-in Self creates your organization for you; it owns flows, API keys, webhook subscriptions, and the billing relationship. You can rename it under Settings → General and invite teammates from Settings → People.
2. Create a flow
The dashboard home shows a card for each of the core workspaces:
- Pre-KYC: identity attributes (document, age, country rules, OFAC, optional data reveals).
- Age Verification: a minimum age (for example 18 or 21), nothing else.
- Proof of Human: one person, one account.
- Sovereign: a nationality allowlist.
(Custom Config, the fifth workspace, is in early access on the Enterprise plan and lives in the sidebar.)
Most workspaces also offer a Security level, an OFAC toggle, and a Verification mode; keep the defaults for this walkthrough.
Open a workspace and click new config. For this walkthrough, Age Verification is the quickest: set a minimum age and click Deploy. (The config name is edited inline in the page title, and the org name/icon live under Settings → General, see Configure a workspace.)
Once deployed, your configuration has a flowId, shown on the workspace’s Test and Live tabs. Copy it.
Test vs. live: the same
flowIdserves both environments: the API key decides. Sessions created with a test key (sk_test_…) accept mock passports and never bill credits. See Test vs. live.
3. Create an API key
Go to Developer → API keys, keep the Test tab selected, and click Generate key. The key (sk_test_...) is shown once, store it as SELF_API_KEY in your backend’s secret manager. See API keys.
4. Install the SDK
npm install @selfxyz/enterprise-sdk
5. Create a verification session
import { SelfClient } from '@selfxyz/enterprise-sdk';
const self = new SelfClient({ apiKey: process.env.SELF_API_KEY! });
const session = await self.sessions.create({
flowId: '<paste flowId from step 2>',
externalUuid: user.id, // your stable id for this user (any string up to 256 chars).
});
console.log(session.verificationUrl); // hand this to the user.
The user opens verificationUrl in their Self app, produces a proof, and the app submits it back to us.
6. Add a webhook endpoint
In Developer → Webhooks, select the Test tab (the endpoint inherits the environment from the active tab), click Add webhook, paste the full URL to your handler (e.g. https://<your-tunnel>/webhooks/self, including the path), and click Save. The endpoint saves right away and the dashboard reveals a signing secret (whsec_...) once, store it as SELF_WEBHOOK_SECRET. Every endpoint receives the verification.completed event.
Once your handler (step 7) is deployed, you can hit Send Test Request on the endpoint to confirm it’s reachable. See Webhooks for the full detail.
7. Verify webhook deliveries
// app/api/webhooks/self/route.ts
import { SelfWebhooks } from '@selfxyz/enterprise-sdk';
export async function POST(req: Request) {
const raw = await req.text(); // raw body is required for signature verification.
const headers = Object.fromEntries(req.headers);
try {
const event = SelfWebhooks.verify(raw, headers, process.env.SELF_WEBHOOK_SECRET!);
if (event.type === 'verification.completed') {
// event.verification_id, event.external_uuid, event.proof_attributes.
console.log('verified:', event);
}
return new Response('ok', { status: 200 });
} catch (err) {
return new Response('bad signature', { status: 400 });
}
}
8. Test the loop
Create a mock passport in the Self app (on the app’s first screen, tap the Passport button five times), then open the verificationUrl from step 5, scan the QR code, and watch your webhook handler fire. The dashboard’s Activity log tab on the flow shows the verification end-to-end.
Thanks — what went wrong?
Thanks for your feedback!